// StiPattern.cpp: implementation of the CStiPattern class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CrossStitch.h"
#include "StiLibMng.h"
#include <map>
#include <atlimage.h>

#include "StiPattern.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CStiPattern::CStiPattern()
{
	m_Width = 40;
	m_Height = 30;
	m_pStiMap = NULL;

}

CStiPattern::~CStiPattern()
{
	if (m_pStiMap)
	{
		delete[] m_pStiMap;
		m_pStiMap = NULL;
	}
}

int CStiPattern::Import( CString str, int* result)
{
	CImage bmp;
	HRESULT hr = bmp.Load(str);
	if (hr!= S_OK)
		return -1;

	m_Width = bmp.GetWidth();
	m_Height = bmp.GetHeight();
	int pitch = bmp.GetPitch();
	this->CreatePattern(m_Width, m_Height);
	unsigned char* pBuf = (unsigned char* )bmp.GetBits();
	CList<unsigned int, unsigned int> mapd;
	for (int j=0; j<m_Height; j++)
	{
		for (int i=0; i<m_Width; i++)
		{
			unsigned int sti = *(pBuf+3*i)<<16| *(pBuf+3*i+1)<<8 |*(pBuf+3*i+2);
			POSITION pos = mapd.Find(sti);
			if (!pos)
			{
				pos = mapd.AddTail(sti);
			}

			*(m_pStiMap+i+j*m_Width) = pos;
		}
		pBuf +=pitch;
	}
	POSITION pos = mapd.GetHeadPosition();
	int mWeight = 0;
	CStiFlossTable sft;
	while (pos)
	{
		POSITION old = pos;
		unsigned int color = mapd.GetNext(pos);
		
// 		color = (color&0xFF)<<16 | (color&0xFF00)| (color&0xFF0000)>>16 ;
		FLOSS* p = NULL;
		mWeight += CStiLibMng::instance()->GetLib("DMC")->MatchFloss(color, &p);
//		POSITION posFloss = m_StiFlossTable.GetFlossList()->AddTail(floss);
		POSITION posFloss = sft.GetFlossList()->Find(p);
		if (!posFloss)
		{
			//FLOSS* floss = new FLOSS(*p);
			//floss->color = p->color;
			posFloss = sft.GetFlossList()->AddTail(p);
		}

		for (int i=0;i<m_Height*m_Width; i++)
		{
			if (*(m_pStiMap+i) == old)
				*(m_pStiMap+i) = posFloss;
		}
	}
	pos = sft.GetFlossList()->GetHeadPosition();
	while (pos)
	{
		POSITION old = pos;
		FLOSS* p = sft.GetFlossList()->GetNext(pos);
		
		FLOSS* floss = new FLOSS(*p);

		POSITION posFloss = m_StiFlossTable.GetFlossList()->AddTail(floss);
		for (int i=0;i<m_Height*m_Width; i++)
		{
			if (*(m_pStiMap+i) == old)
				*(m_pStiMap+i) = posFloss;
		}
	}

	sft.GetFlossList()->RemoveAll();

	mWeight /= m_Width*m_Height;
	*result = mWeight;
	return 0;
}

void CStiPattern::Import( CString fileName, CONFIG& conf )
{
	for (int i=0; i<m_Width*m_Height; i++)
	{
		int count = CStiLibMng::instance()->GetLib("")->GetFlosses()->GetCount()+1;
		int rp = rand()%count;
		if (rp)
		{
			*(m_pStiMap+i) = CStiLibMng::instance()->GetLib("")->GetFlosses()->GetFlossList()->FindIndex(rp-1);
		}
	}
}

void CStiPattern::Open( CString fileName )
{
	
}

void CStiPattern::Clear()
{
	
}

void CStiPattern::Draw( CDC* pDC, int sx, int sy, UINT nGrid/*=0*/, UINT viewMode /*= VM_NORMAL*/, UINT zoom /*= 100*/ )
{
	CPen penFrame, penLine, penMainLine;
	penFrame.CreatePen(PS_SOLID, 4, RGB(0,0,0));
	penLine.CreatePen(PS_SOLID, 1, RGB(0,0,0));
	penMainLine.CreatePen(PS_SOLID, 2, RGB(0,0,0));

	CGdiObject* old = NULL;
	int l,t,r,b,w,h;
	int invx, invy;
	invx = POINT_CX;
	invy = POINT_CY;
	int mx = STITCH_GRID_NUMBER*invx;
	int my = STITCH_GRID_NUMBER*invy;

	l = sx;
	t = sy;
	int dx = 0, dy = 0;
	if (nGrid)
	{
		dx = m_Width + m_Width/STITCH_GRID_NUMBER + 1;
		dy = m_Height + m_Height/STITCH_GRID_NUMBER + 1;
	}
	r = l+invx*m_Width + dx;
	b = t+invy*m_Height + dy;
	w = invx*m_Width;
	h = invy*m_Height;

	int idx = 0;
	int ac = m_Width* m_Height; // width and height must be 10*
	int wide = m_Width;
	int hight = m_Height;

	old = pDC->SelectObject(&penFrame);
	CRect rectFrame(l, t, r, b);
	rectFrame.InflateRect(2,2);
	rectFrame += CPoint(1,1);
	pDC->Rectangle(rectFrame); // draw the frame
	int interx, intery;

	if (nGrid == 0)  // not show grid
	{
		for (idx=0;idx<ac; idx++)
		{
			POSITION pos = *(m_pStiMap+idx);
			if (pos)
			{
				FLOSS* floss = m_StiFlossTable.GetFlossList()->GetAt(pos);
				if (floss)
				{
// 					interx = (idx%wide)+(idx%wide)/5+((idx%wide)>=(wide/2)+2)*2+1;
// 					intery = (idx/wide)+(idx/wide)/5+((idx/wide)>=(hight/2)+2)*2+1;
					pDC->FillSolidRect(l+invx*(idx%wide), t+invy*(idx/wide), invx, invy, floss->color); // draw point
				}
			}
		}
	}
	else
	{
		for (idx=0;idx<ac; idx++)
		{
			POSITION pos = *(m_pStiMap+idx);
			if (pos)
			{
				FLOSS* floss = m_StiFlossTable.GetFlossList()->GetAt(pos);
				if (floss)
				{
					int x = idx%wide;
					int y = idx/wide;
					interx = x+x/STITCH_GRID_NUMBER+(2*x>=wide)*2+1;
					intery = y+y/STITCH_GRID_NUMBER+(2*y>=hight)*2+1;
					pDC->FillSolidRect(l+invx*x+interx, t+invy*y+intery, invx, invy, floss->color); // draw point
				}
			}
		}

		pDC->SelectObject(&penLine); // draw grids for points
		int i = 0;
		int cntLine;
		cntLine = w/invx;
		for (i=0; i<cntLine; i++)
		{
			interx = i+i/STITCH_GRID_NUMBER+(i>=cntLine/2)*2;
			pDC->MoveTo(invx*i+l+interx, t);
			pDC->LineTo(invx*i+l+interx, b);
		}
		cntLine = h/invy;
		for (i=0; i<cntLine; i++)
		{
			intery = i+i/STITCH_GRID_NUMBER+(i>=(cntLine/2))*2;
			pDC->MoveTo(l, invy*i+intery+t);
			pDC->LineTo(r, invy*i+intery+t);
		}

		pDC->SelectObject(&penMainLine); // draw main grid and middle partition grid
		cntLine = w/mx;
		for (i=0; i<cntLine; i++)
		{
			interx = i*STITCH_GRID_NUMBER+i+((i>=(cntLine/2)))*2;
			if (i==cntLine/2)
			{
				pDC->SelectObject(&penFrame);
				interx -= 2;
			}
			else
			{
				pDC->SelectObject(&penMainLine);
			}
			pDC->MoveTo(mx*i+l+interx, t);
			pDC->LineTo(mx*i+l+interx, b);
		}
		cntLine = h/my;
		for (i=0; i<cntLine; i++)
		{
			intery = i*STITCH_GRID_NUMBER+i+((i>=(cntLine/2)))*2;
			if (i==cntLine/2)
			{
				pDC->SelectObject(&penFrame);
				intery -= 2;
			}
			else
			{
				pDC->SelectObject(&penMainLine);
			}
			pDC->MoveTo(l, my*i+intery+t);
			pDC->LineTo(r, my*i+intery+t);
			//if (i==h/(2*my))
			//{
			//	pDC->SelectObject(&penMainLine);
			//}
		}

	}

	pDC->SelectObject(old);

}

void CStiPattern::PreProcess()
{
	
}

void CStiPattern::PostProcess()
{
	
}

void CStiPattern::SetPoint( int x, int y, FLOSS* floss )
{
	if (x<0 || x>=m_Width || y<0 || y>=m_Height)
	{
		return;
	}
	POSITION idx = m_StiFlossTable.Find(floss);
	*(m_pStiMap+y*m_Width+x) = idx;
}

void CStiPattern::FloodPoint( int x, int y, FLOSS* floss, FLOSS* old )
{
	if (x<0 || x>=m_Width || y<0 || y>=m_Height)
	{
		return;
	}
	FLOSS* now = GetPoint(x,y);
	if (now == old)
	{
		POSITION idx = m_StiFlossTable.Find(floss);
		*(m_pStiMap+y*m_Width+x) = idx;
	}
	else
		return;
	FloodPoint(x-1, y, floss, old);
	FloodPoint(x+1, y, floss, old);
	FloodPoint(x, y-1, floss, old);
	FloodPoint(x, y+1, floss, old);

}

void CStiPattern::FloodPoint( int x, int y, FLOSS* floss )
{
	if (x<0 || x>=m_Width || y<0 || y>=m_Height)
	{
		return;
	}
	FLOSS* old = GetPoint(x,y);
	if (old != floss)
	{
		POSITION idx = m_StiFlossTable.Find(floss);
		*(m_pStiMap+y*m_Width+x) = idx;
		FloodPoint(x-1, y, floss, old);
		FloodPoint(x+1, y, floss, old);
		FloodPoint(x, y-1, floss, old);
		FloodPoint(x, y+1, floss, old);
	}
}

FLOSS* CStiPattern::GetPoint( int x, int y )
{
	if (m_pStiMap == NULL)
	{
		return NULL;
	}
	if (x<0 || x>=m_Width || y<0 || y>=m_Height)
	{
		return NULL;
	}
	POSITION pos = *(m_pStiMap+y*m_Width+x);
	if (pos == 0)
	{
		return NULL;
	}
	return m_StiFlossTable.Find(pos);
}

void CStiPattern::RemovePoint( int x, int y )
{
	*(m_pStiMap+y*m_Width +x) = m_StiFlossTable.GetFlossList()->GetHeadPosition();
	
}

void CStiPattern::MoveRect( CRect rect, CSize offset )
{
	
}

void CStiPattern::Erase( int x, int y, BYTE ersPat )
{
	
}

int CStiPattern::CreatePattern( int w, int h )
{
	if (m_pStiMap != NULL)
	{
		delete[] m_pStiMap;
		m_pStiMap = NULL;
	}
	m_StiFlossTable.Clear();
	m_pStiMap = new POSITION[w*h];
	memset(m_pStiMap, 0, sizeof(POSITION)*w*h);
	m_Width = w;
	m_Height = h;

	return 0;
}

void CStiPattern::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
		ar << m_Width;
		ar << m_Height;
		m_StiFlossTable.Serialize(ar);
		for (int i=0; i<m_Width*m_Height; i++)
		{
			BYTE sym = m_StiFlossTable.GetIndex(*(m_pStiMap+i));
			ar << sym;
		}
	}
	else
	{
		// TODO: add loading code here
		ar >> m_Width;
		ar >> m_Height;
		CreatePattern(m_Width, m_Height);
		m_StiFlossTable.Serialize(ar);
		BYTE sym=0;
		for (int i=0; i<m_Width*m_Height; i++)
		{
			ar >> sym;
			if (sym)
			{
				POSITION pos = m_StiFlossTable.GetFlossList()->FindIndex(sym-1);
				*(m_pStiMap+i) = pos;
			}
// 			else
// 				*(m_pStiMap+i) = m_StiFlossTable.GetFlossList()->GetHeadPosition();
		}
	}

}

void CStiPattern::DrawFlossTable( CDC* pDC, int sx, int sy )
{
	m_StiFlossTable.DrawFlossTable(pDC, sx, sy, 80);
}


